#ifndef BASE_PHYSICALSOCKETSERVER_H__
#define BASE_PHYSICALSOCKETSERVER_H__

#include <vector>

//#include "asyncfile.h"
#include "scoped_ptr.h"
#include "socketserver.h"
#include "criticalsection.h"
#include "winping.h"

#ifdef POSIX
typedef int SOCKET;
#endif // POSIX

namespace base
{

	// Event constants for the Dispatcher class.
	enum DispatcherEvent
	{
		DE_READ    = 0x0001,
		DE_WRITE   = 0x0002,
		DE_CONNECT = 0x0004,
		DE_CLOSE   = 0x0008,
		DE_ACCEPT  = 0x0010,
	};

	class Signaler;
#ifdef POSIX
	class PosixSignalDispatcher;
#endif

	class Dispatcher
	{
	public:
		virtual ~Dispatcher() {}
		virtual uint32 GetRequestedEvents() = 0;
		virtual void OnPreEvent(uint32 ff) = 0;
		virtual void OnEvent(uint32 ff, int err) = 0;
#ifdef WIN32
		virtual WSAEVENT GetWSAEvent() = 0;
		virtual SOCKET GetSocket() = 0;
		virtual bool CheckSignalClose() = 0;
#elif POSIX
		virtual int GetDescriptor() = 0;
		virtual bool IsDescriptorClosed() = 0;
#endif
	};

	// A socket server that provides the real sockets of the underlying OS.
	class PhysicalSocketServer : public SocketServer
	{
	public:
		PhysicalSocketServer();
		virtual ~PhysicalSocketServer();

		// SocketFactory:
		virtual Socket* CreateSocket(int type);
		virtual Socket* CreateSocket(int family, int type);

		virtual AsyncSocket* CreateAsyncSocket(int type);
		virtual AsyncSocket* CreateAsyncSocket(int family, int type);

		// Internal Factory for Accept
		AsyncSocket* WrapSocket(SOCKET s);

		// SocketServer:
		virtual bool Wait(int cms, bool process_io);
		virtual void WakeUp();

		void Add(Dispatcher* dispatcher);
		void Remove(Dispatcher* dispatcher);

#ifdef POSIX
		AsyncFile* CreateFile(int fd);

		// Sets the function to be executed in response to the specified POSIX signal.
		// The function is executed from inside Wait() using the "self-pipe trick"--
		// regardless of which thread receives the signal--and hence can safely
		// manipulate user-level data structures.
		// "handler" may be SIG_IGN, SIG_DFL, or a user-specified function, just like
		// with signal(2).
		// Only one PhysicalSocketServer should have user-level signal handlers.
		// Dispatching signals on multiple PhysicalSocketServers is not reliable.
		// The signal mask is not modified. It is the caller's responsibily to
		// maintain it as desired.
		virtual bool SetPosixSignalHandler(int signum, void (*handler)(int));

	protected:
		Dispatcher* signal_dispatcher();
#endif

	private:
		typedef std::vector<Dispatcher*> DispatcherList;
		typedef std::vector<size_t*> IteratorList;

#ifdef POSIX
		static bool InstallSignal(int signum, void (*handler)(int));

		scoped_ptr<PosixSignalDispatcher> signal_dispatcher_;
#endif
		DispatcherList dispatchers_;
		IteratorList iterators_;
		Signaler* signal_wakeup_;
		CriticalSection crit_;
		bool fWait_;
		uint32 last_tick_tracked_;
		int last_tick_dispatch_count_;
#ifdef WIN32
		WSAEVENT socket_ev_;
#endif
	};

} // namespace base

#endif // BASE_PHYSICALSOCKETSERVER_H__
